#pragma once

#include <string>
#include <unordered_map>
#include <functional>
#include <fstream>
#include <sstream>
#include <cstring>

#include <cereal/types/memory.hpp>
#include <cereal/archives/binary.hpp>
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/unordered_map.hpp>
#include <cereal/types/tuple.hpp>


namespace lurpc {

template<typename R, typename ... Args>
struct service_type_traits {
    static std::string serialize(const R& _r) {
        std::ostringstream _os;
        cereal::BinaryOutputArchive _arch(_os);
        _arch(_r);
        return _os.str();
    }

    static std::tuple<Args...> deserialize(const std::string& _buf) {
        std::tuple<Args...> _ans;
        std::istringstream _is(_buf);
        cereal::BinaryInputArchive _arch(_is);
        _arch(_ans);
        return _ans;
    }

    using return_t = R;
    using param_tp = std::tuple<Args...>;
};


class server_stub {
public:
    static void register_service(uint32_t _id, std::string(*_handler)(const std::string&)) {
        _services[_id] = _handler;
    }

    static auto get_service(uint32_t _id) -> std::string(*)(const std::string&) {
        return _services.find(_id) == _services.end() ? nullptr : _services[_id];
    }

private:
    static std::unordered_map<uint32_t, std::string(*)(const std::string&)> _services;
};

std::unordered_map<uint32_t, std::string(*)(const std::string&)> server_stub::_services;


}
